package com.geeguo.ebuilder.operation.business.tenant.tenantinfo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.geeguo.ebuilder.core.common.dictionary.StateEnum;
import com.geeguo.ebuilder.core.common.model.vo.PageListVO;
import com.geeguo.ebuilder.core.common.utils.GsonUtils;
import com.geeguo.ebuilder.core.common.utils.ObjectEqualsHelper;
import com.geeguo.ebuilder.core.common.utils.PageUtils;
import com.geeguo.ebuilder.core.common.utils.SqlHelper;
import com.geeguo.ebuilder.core.redis.constants.CacheTimeConstants;
import com.geeguo.ebuilder.core.redis.service.RedisCacheService;
import com.geeguo.ebuilder.operation.base.redis.utils.CacheKeyFactory;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.mapper.TenantInfoMapper;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.model.TenantInfoConverter;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.model.TenantInfoEntity;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.model.TenantInfoQuery;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.model.TenantInfoCO;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.model.TenantInfoVO;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.producer.TenantInfoMQProducer;
import com.geeguo.ebuilder.operation.business.tenant.tenantinfo.service.TenantInfoService;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Slf4j
@Service
public class TenantInfoServiceImpl implements TenantInfoService {

    @Autowired
    private TenantInfoMapper tenantInfoMapper;
    @Autowired
    private RedisCacheService redisCacheService;
    @Autowired
    private TenantInfoMQProducer tenantInfoMQProducer;

    @Override
    public PageListVO<TenantInfoVO> list(TenantInfoQuery query) {
        Map<String, Object> params = new HashMap<>();
        if (StringUtils.isNotEmpty(query.getCode())) {
            params.put("code", SqlHelper.getFullImplict(query.getCode()));
        }
        if (StringUtils.isNotEmpty(query.getName())) {
            params.put("name", SqlHelper.getFullImplict(query.getName()));
        }
        if (query.getState() != null && query.getState() > 0) {
            params.put("state", query.getState());
        }
        IPage<TenantInfoEntity> page = tenantInfoMapper.list(new Page<>(query.getPageNo(), query.getPageSize()), params);
        List<TenantInfoVO> result = new ArrayList<>();
        if (page.getRecords() != null && !page.getRecords().isEmpty()) {
            for (TenantInfoEntity item : page.getRecords()) {
                result.add(TenantInfoConverter.INSTANCE.convert2VO(item));
            }
        }
        return PageUtils.getPageListVO(page, result);
    }

    @Override
    public List<TenantInfoVO> listValid() {
        LambdaQueryWrapper<TenantInfoEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TenantInfoEntity::getState, StateEnum.Valid.getValue());
        List<TenantInfoEntity> list = tenantInfoMapper.selectList(queryWrapper);
        List<TenantInfoVO> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (TenantInfoEntity entity : list) {
                result.add(TenantInfoConverter.INSTANCE.convert2VO(entity));
            }
        }
        return result;
    }

    @Override
    public TenantInfoVO get(String id) {
        TenantInfoEntity result = tenantInfoMapper.selectById(id);
        if (result != null) {
            return TenantInfoConverter.INSTANCE.convert2VO(result);
        }
        return null;
    }

    @Override
    public TenantInfoVO getByCode(String code) {
        TenantInfoVO result = null;
        if (StringUtils.isNotEmpty(code)) {
            LambdaQueryWrapper<TenantInfoEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TenantInfoEntity::getCode, code);
            TenantInfoEntity entity = tenantInfoMapper.selectOne(queryWrapper);
            if (entity != null) {
                result = TenantInfoConverter.INSTANCE.convert2VO(entity);
            }
        }
        return result;
    }

    @Override
    public TenantInfoVO getByDomain(String domain) {
        TenantInfoVO result = null;
        if (StringUtils.isNotEmpty(domain)) {
            LambdaQueryWrapper<TenantInfoEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TenantInfoEntity::getDomain, domain);
            TenantInfoEntity entity = tenantInfoMapper.selectOne(queryWrapper);
            if (entity != null) {
                result = TenantInfoConverter.INSTANCE.convert2VO(entity);
            }
        }
        return result;
    }

    @Override
    public TenantInfoCO getCached(String id) {
        TenantInfoCO result = null;
        String cacheKey = CacheKeyFactory.INSTANCE.getTenantInfo(id);
        String cacheJson = redisCacheService.get(cacheKey);
        if (StringUtils.isNotEmpty(cacheJson)) {
            result = GsonUtils.fromJson(cacheJson, TenantInfoCO.class);
        }
        if (result == null) {
            TenantInfoEntity entity = tenantInfoMapper.selectById(id);
            if (entity != null) {
                result = TenantInfoConverter.INSTANCE.convert2CO(entity);
                cacheJson = GsonUtils.toJson(result);
                redisCacheService.set(cacheKey, cacheJson, CacheTimeConstants.CACHE_WEEK);
            }
        }
        return result;
    }
    
    @Override
    public boolean save(TenantInfoEntity entity) {
        return tenantInfoMapper.insert(entity) > 0;
    }
    
    @Override
    public boolean update(TenantInfoEntity current, TenantInfoEntity old) {
        Map<String, Object> changeValues = ObjectEqualsHelper.equals(current, old, new String[] {"code", "name", "domain", "dataSourceId", "configJson", "state"});
        if (changeValues.isEmpty()) {
            return true;
        } else {
            changeValues.put("id", current.getId());
            changeValues.put("modifyTime", current.getModifyTime());
            changeValues.put("modifyUser", current.getModifyUser());
            boolean result = tenantInfoMapper.updateByParams(changeValues) == 1;
            if (result) {
                removeCached(current.getId());
                tenantInfoMQProducer.sendChangeMessage(old.getCode());
            }
            return result;
        }
    }
    
    @Override
    public boolean remove(String id) {
        boolean result = true;
        TenantInfoEntity entity = tenantInfoMapper.selectById(id);
        if (entity != null) {
            result = tenantInfoMapper.deleteById(id) == 1;
            if (result) {
                removeCached(id);
                tenantInfoMQProducer.sendChangeMessage(entity.getCode());
            }
        }
        return result;
    }

    private void removeCached(String id) {
        String cacheKey = CacheKeyFactory.INSTANCE.getTenantInfo(id);
        redisCacheService.del(cacheKey);
    }
}
